package com.lry.basic.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadLocalVariableHolder3 {
    private static ThreadLocal<Integer> variableHolder = new InheritableThreadLocal<Integer>();

    public static void setValue(int val) {
        variableHolder.set(val);
    }

    public static int getValue() {
        return variableHolder.get();
    }

    public static void remove() {
        variableHolder.remove();
    }

    public static void increment() {
        variableHolder.set(variableHolder.get() + 1);
    }


    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        variableHolder.set(0);

        //线程池会复用线程，使用完线程后一定要清楚threadLocal，不然去执行新任务的时候会使用上一次的threadLocal产生错误结果
        for (int i = 0; i < 5; i++) {
            int finalI = i;
            executor.execute(

                    TtlRunnable2.get(
                       () -> {
                           if(finalI ==0){
                               setValue(100);
                           }
                           long threadId = Thread.currentThread().getId();
                           System.out.println("threadId: " + threadId + ", value: " + getValue());
//                        int before = getValue();
//                        long threadId = Thread.currentThread().getId();
//                        increment();
//                        int after = getValue();
//                        System.out.println("threadId: " + threadId + ", before: " + before + ", after: " + after);
                    },variableHolder)

            );
        }

        executor.shutdown();
    }

//    JDK的InheritableThreadLocal类可以完成父线程到子线程的值传递。
//    但对于使用线程池等会池化复用线程的组件的情况，线程由线程池创建好，
//    并且线程是池化起来反复使用的；这时父子线程关系的ThreadLocal值传递已经没有意义，
//    应用需要的实际上是把任务提交给线程池时的ThreadLocal值传递到任务执行时。

}

class TtlRunnable2 implements Runnable{

    private Runnable task;
    private ThreadLocal<Integer> tl;

    private TtlRunnable2(Runnable task, ThreadLocal<Integer> tl) {
        this.task = task;
        this.tl = tl;
    }

    public static Runnable get(Runnable task,ThreadLocal<Integer> tl){
        return new TtlRunnable2(task,tl);
    }

    @Override
    public void run() {
        //备份线程执行之前threadLocal的值
        int back = tl.get();
        try {
            this.task.run();
        } finally {
            //线程执行完后给恢复回去
            tl.set(back);
        }
    }
}